package com.spingboot.study.aspect;
// 导入自定义注解 RateLimit
import com.spingboot.study.annotation.RateLimit;
// 导入 AOP 相关类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 导入线程安全的 HashMap
import java.util.concurrent.ConcurrentHashMap;
// 声明这是一个切面类（Aspect）
@Aspect
// 声明这是一个 Spring 管理的组件（Bean）
@Component
public class RateLimitAspect {
    // 用于存储每个用户的上次访问时间
    // key: userId + 方法名，value: 上次调用时间（毫秒）
    private final ConcurrentHashMap<String, Long> requestMap = new ConcurrentHashMap<>();

    // 环绕通知：拦截被 @RateLimit 注解标注的方法
    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        // 获取方法参数列表
        Object[] args = joinPoint.getArgs();
        // 如果方法没有参数，则直接执行目标方法
        if (args.length == 0) {
            return joinPoint.proceed();
        }
        // 假设第一个参数是用户ID
        String userId = args[0].toString();
        // 构造唯一 key：用户ID + 方法名，用于记录该用户访问该方法的时间
        String key = userId + "_" + joinPoint.getSignature().getName();
        // 获取当前时间（毫秒）
        long now = System.currentTimeMillis();
        // 获取该用户上次访问时间
        Long lastTime = requestMap.get(key);
        // 如果上次访问时间存在，并且距离现在小于注解中设置的限流时间，则触发限流
        if (lastTime != null && (now - lastTime) < rateLimit.time()) {
            // 返回提示信息，不执行目标方法
            return "请求过于频繁，请稍后再试";
        }
        // 更新该用户访问该方法的最新时间
        requestMap.put(key, now);
        // 执行目标方法，并返回结果
        return joinPoint.proceed();
    }
}
